Locking is the method by which SQL Server controls
who has what access to what data within the table. Every command that
is run in the database takes some sort of lock against SQL Server.
There are seven basic kinds of locks that can be taken and four
different levels. These levels are at the row level, page level, table
level, or database level. SQL Server will automatically escalate locks
from row to page to table as it becomes more efficient to take the lock
at the higher level. SQL Server will never escalate a lock from the
table level to the database level. Locks at the database level are taken only when specific database options are changed via the ALTER DATABASE command.
The
kinds of locks that can be taken are the same for the row, page, and
table levels. They fall into two groups: basic locks and extended
locks. The basic locks are shared (S), update (U), and exclusive (X).
These three locks can then be modified as needed by the extended locks,
which are intent (I), schema (Sch), bulk update (BU), and key-range
(KR). How these extended locks are combined with the basic locks is
described a little later in this section.
The
shared lock is taken when reading a table with a select statement. This
lock allows other shared locks to be taken by other transactions
attempting to read the data. No transaction can update data that is
locked by a shared lock until the shared lock has been released.
The
update lock is taken when updating the rows of a table. This update
lock is used while SQL Server is reading the rows that will be
modified. When the rows are being modified this update lock is
converted to an exclusive lock. This is done to prevent two
transactions, both using update statements to cause a deadlock. Without
the update lock when an update statement is issued SQL Server would
take a shared lock while reading the table, then convert that to an
exclusive lock when changing the data. The problem would occur when two
update commands were running against the same set of data. Both would
take a shared lock while reading the table, and then neither would be
able to convert that shared lock to an exclusive lock because of the
other shared lock.
The
exclusive lock is used to prevent any other process from accessing the
locked resource. Read operations can take place against an exclusive
lock only when a NOLOCK hint is used or the reading transaction is
using the READ UNCOMMITTED isolation level. All other operations
against a resource with an exclusive lock will be blocked until the
exclusive lock is released.
There
are six different types of intent locks that can be taken against a
resource. These intent locks are used for a variety of things.
The
intent shared (IS) lock protects requested or acquired shared locks on
some lower level resources. If a shared lock is taken on a record, an
intent shared lock could be taken on the database page that holds that
record.
The intent
exclusive (IX) locks required or acquired exclusive locks on some lower
level resources. The intent exclusive lock is a superset of the intent
shared lock. If an exclusive lock is placed on a record an intent
exclusive lock could be taken on the page that holds that record.
The
shared with intent exclusive (SIX) lock protects shared locks on the
resources lower in the locking hierarchy and intent exclusive locks on
some resources
that are lower in the locking hierarchy. Acquiring a shared with intent
exclusive lock on a table also takes intent exclusive locks on the
pages being modified, or exclusive locks on the rows being modified.
Although there can only be one shared with intent exclusive lock per
table at a time, preventing changes by other transactions, while
allowing other transactions to read the rows and pages in the table by
obtaining intent shared locks at the table level.
The
intent update (IU) lock protects shared or requested lock pages in the
table being updated. Intent update locks are converted to intent
exclusive locks when the update operation takes place.
The
shared intent update lock is a combination of shared and intent update
locks. This lock is taken when a transaction first takes a shared lock
by reading the table from one statement, then by performing an update
through a second statement. This is done most often by using the
PAGLOCK table hint within the select statement that takes the shared
lock. The update statement then takes an intent update lock, which is
then escalated to a shared intent update lock as it is more efficient
for SQL Server to manage a single lock than multiple locks.
Exercise . Viewing Locks
Open two query windows in SQL Server Management Studio. In the first use the BEGIN TRANSACTION statement and an update statement. This will begin the transaction and hold the locks on the objects. In
the second window use the sys.dm_tran_locks dynamic management view.
Use this dynamic management view to see what locks were taken. Roll back the query in the first window, and run other statements. Change the isolation level of the transaction in the first window, and rerun the statements. Rerun the sp_lock procedure and see how the locks have changed.
|
The
update intent exclusive lock is a combination of update and intent
exclusive locks being taken at different times but held at the same
time. Like the shared intent update lock it is more efficient to hold
one lock than two locks.
When
DDL statements are run against the objects in the database, they use
schema modification locks (Sch-M) to prevent access to the object in
which the DDL statement is run. This schema modification lock prevents
all access to the object by any other statements until the schema modification lock is released. When a TRUNCATE TABLE
command is issued against a table a schema modification lock is taken
against the table for the duration of the time it takes for the
truncate statement to be completed.
When
SQL Server is compiling and executing statements it takes a schema
stability lock against the objects in question. The schema stability
lock does not block any object level locks, including the exclusive
lock. It does block the schema modification lock, however, from being
taken until after the schema stability lock has been released.
The
database engine uses bulk update locks (BU) when bulk copying data into
a table through bcp, bulk insert, Integration Services, and so on, and
either the TABLOCK table hint is used, or the “table lock on bulk load”
table option is set using the sp_tableoption
system stored procedure. The bulk update lock allows multiple threads
to bulk load data into the table, while blocking other processes from
accessing the table. When using bcp you can force the BU lock to be
taken by specifying the –h switch in the command line and adding the TABLOCK hint. When using the BULK INSERT statement, simply specify the TABLOCK switch in the command. When using SQL Server Integration Services to bulk load data, check the Table lock check box as shown in Figure 1.
Key
range locks protect a set of rows included within a record set being
read by a T/SQL statement while using the serializable transaction
isolation level. By protecting the range of rows being worked with it
prevents phantom inserts, deletes, or reads against the protected rows.
If you wish to manually take locks against the database objects you can use the system stored procedure sp_getapplock.
This procedure allows you to specify the object you wish to lock, the
lock type you wish to take, the owner of the lock, and the length of
time that the lock will last. If a lock taken with sp_getapplock doesn’t time out, or you take the lock without a timeout, you can use the sp_releaseapplock
system stored procedure to release the lock that you took. This
procedure takes the same basic parameters, asking for the object name
and lock owner. When you use these procedures they must be used within
an explicit transaction.